package main

import (
	"fmt"
	"net"
	"os"
	"strconv"
	"strings"
	"time"
)

/*
net包来创建一个服务器端程序，在服务器端我们需要绑定服务到指定的非激活端口，并监听此端口，当有客户端请求到达的时候可以接收到来自客户端连接的请求
func ListenTCP(network string, laddr *TCPAddr) (*TCPListener, error)
func (l *TCPListener) Accept() (Conn, error)

控制TCP连接
func DialTimeout(net, addr string, timeout time.Duration) (Conn, error) 设置建立连接的超时时间，客户端和服务器端都适用，当超过设置时间时，连接自动关闭。
func (c *TCPConn) SetReadDeadline(t time.Time) error  用来设置写入/读取一个连接的超时时间。当超过设置时间时，连接自动关闭。
func (c *TCPConn) SetWriteDeadline(t time.Time) error
func (c *TCPConn) SetKeepAlive(keepalive bool) os.Error 设置keepAlive属性。操作系统层在tcp上没有数据和ACK的时候，会间隔性的发送keepalive包，操作系统可以通过该包来判断一个tcp连接是否已经断开，
  在windows上默认2个小时没有收到数据和keepalive包的时候认为tcp连接已经断开，这个功能和我们通常在应用层加的心跳包的功能类似。
*/

// 服务端：多任务，应答
func main() {
	service := ":8999"
	tcpAddr, err := net.ResolveTCPAddr("tcp4", service)
	checkErr(err)
	listener, err := net.ListenTCP("tcp", tcpAddr)
	checkErr(err)
	for {
		conn, err := listener.Accept()
		if err != nil {
			continue
		}
		go handleClient(conn)
	}
}

func handleClient(conn net.Conn) {
	conn.SetReadDeadline(time.Now().Add(2 * time.Minute)) // 2分钟后过期
	request := make([]byte, 128)                          // 最多128B，request在创建时需要指定一个最大长度以防止flood attack
	defer conn.Close()
	for {
		read_len, err := conn.Read(request)
		if err != nil {
			fmt.Println(err)
			break
		}
		if read_len == 0 {
			break // already closed by client
		} else if readStr := strings.TrimSpace(string(request[:read_len])); readStr == "timestamp" {
			fmt.Println("read from client:", readStr)
			daytime := strconv.FormatInt(time.Now().Unix(), 10)
			conn.Write([]byte(daytime))
		} else {
			fmt.Println("read from client:", readStr)
			daytime := time.Now().String()
			conn.Write([]byte(daytime))
		}
		request = make([]byte, 128) // clear last read content
	}
}

func checkErr(err error) {
	if err != nil {
		fmt.Fprintf(os.Stderr, "Fata error: %s", err.Error())
		os.Exit(1)
	}
}
